﻿Imports Bring2mind.DNN.Modules.DMX.Entities.Entries
Imports Telerik.Web.UI.Widgets
Imports System.Web
Imports System

Imports DotNetNuke.Common.Globals
Imports DotNetNuke.Entities.Portals
Imports System.IO

Imports System.Collections.Generic
Imports Bring2mind.DNN.Modules.DMX.Common

Imports Bring2mind.DNN.Modules.DMX.Security
Imports DotNetNuke.Common.Utilities

Public Class ContentProvider
 Inherits FileSystemContentProvider

#Region " Private Members "

 Private _itemHandlerPath As String

 Private ReadOnly Property ItemHandlerPath() As String
  Get
   Return _itemHandlerPath
  End Get
 End Property

 Private Portalsettings As PortalSettings = Nothing

 Private ReadOnly Property PortalId() As Integer
  Get
   Return Portalsettings.PortalId
  End Get
 End Property

 Private _userId As Integer = -2
 Private ReadOnly Property UserId() As Integer
  Get
   If _userId < -1 Then
    If Portalsettings.UserInfo.IsSuperUser Then
     _userId = Portalsettings.AdministratorId
    Else
     _userId = Portalsettings.UserId
    End If
   End If
   Return _userId
  End Get
 End Property

 Private _dmxPath As String
 Public Property DMXPath() As String
  Get
   Return _dmxPath
  End Get
  Set(ByVal value As String)
   _dmxPath = value
  End Set
 End Property

#End Region

#Region " Overrides "

 Public Sub New( _
     ByVal context As HttpContext, _
     ByVal searchPatterns As String(), _
     ByVal viewPaths As String(), _
     ByVal uploadPaths As String(), _
     ByVal deletePaths As String(), _
     ByVal selectedUrl As String, _
     ByVal selectedItemTag As String)


  MyBase.New( _
      context, _
      searchPatterns, _
      viewPaths, _
      uploadPaths, _
      deletePaths, _
      selectedUrl, _
      selectedItemTag _
  )

  Portalsettings = DotNetNuke.Entities.Portals.PortalController.GetCurrentPortalSettings

  DMXPath = viewPaths(0)

 End Sub


 Public Overrides Function ResolveRootDirectoryAsTree(ByVal path As String) As Telerik.Web.UI.Widgets.DirectoryItem


  'as this method is being called 5 times (!) for each initial load and then again for each ajax call that 
  'loads a given subtree, we need to store the reuslt in the cache
  If Not DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & path) Is Nothing Then
   Return CType(DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & path), Telerik.Web.UI.Widgets.DirectoryItem)
  End If

  Dim ParentFolder As EntryInfo = GetEntryFromPath(path)
  Dim folderPermission As PathPermissions = 0
  Dim childdirectories As DirectoryItem() = New DirectoryItem() {}

  If Not ParentFolder Is Nothing Then

   If ParentFolder.CanAdd Then
    folderPermission = PathPermissions.Read Or PathPermissions.Upload ' removed delete permission
   End If

   childdirectories = GetChildDirectories(ParentFolder, EndWithSlash(path))

  End If

  Dim returnValue As New DirectoryItem( _
      GetName(path), _
      GetDirectoryPath(path), _
      path, _
      String.Empty, _
      folderPermission, _
      New FileItem() {}, _
      childdirectories _
      )

  DataCache.SetCache("DMXRAD_CHILDDIRECTORIES_" & path, returnValue)

  Return returnValue

 End Function

 Public Overrides Function ResolveDirectory(ByVal path As String) As Telerik.Web.UI.Widgets.DirectoryItem

  Dim ParentFolder As EntryInfo = GetEntryFromPath(path)
  Dim folderPermission As PathPermissions = 0
  Dim childfiles As FileItem() = New FileItem() {}
  Dim childdirectories As DirectoryItem() = New DirectoryItem() {}

  If Not ParentFolder Is Nothing Then

   folderPermission = PathPermissions.Read
   childfiles = GetChildFiles(ParentFolder, path)
   childdirectories = GetChildDirectories(ParentFolder, path)

   If ParentFolder.CanAdd Then
    folderPermission = PathPermissions.Read Or PathPermissions.Upload ' removed delete permission
   End If

  End If

  For Each fileItem As FileItem In childfiles
   If String.Compare(fileItem.Extension, "jpg", True) = 0 Or _
       String.Compare(fileItem.Extension, "gif", True) = 0 Or _
       String.Compare(fileItem.Extension, "jpeg", True) = 0 Or _
       String.Compare(fileItem.Extension, "bmp", True) = 0 Or _
       String.Compare(fileItem.Extension, "png", True) = 0 Then
    fileItem.Attributes.Add("Thumb", "<img src=""" & fileItem.Url & """ width=""40"">")
   End If
  Next

  Return New DirectoryItem( _
      GetName(path), _
      EndWithSlash(GetDirectoryPath(path)), _
      String.Empty, _
      String.Empty, _
      folderPermission, _
      childfiles, _
      childdirectories _
      )

 End Function

 'Public Overrides Function ResolveRootDirectoryAsList(ByVal path As String) As Telerik.Web.UI.Widgets.DirectoryItem()
 ' Return MyBase.ResolveRootDirectoryAsList(path)
 'End Function

 Public Overrides ReadOnly Property CanCreateDirectory() As Boolean
  Get
   Return MyBase.CanCreateDirectory
  End Get
 End Property

 Public Overrides Function CreateDirectory(ByVal path As String, ByVal name As String) As String

  Try
   Dim objParent As EntryInfo = GetEntryFromPath(path)
   EntriesController.MakeCollection(PortalId, objParent.EntryId, name, New DMXUser(Portalsettings.UserInfo), False)
  Catch ex As Exception
   Return ex.Message
  End Try
  Return String.Empty

 End Function

 Public Overrides Function DeleteDirectory(ByVal path As String) As String

  Return "You can't delete folders."
  'Try
  ' Dim folder As New System.IO.DirectoryInfo(AbsolutePath(path))
  ' DeleteFolder(Portalsettings.PortalId, folder, CleanPath(path))
  'Catch ex As Exception
  ' Return "You can only delete folders when all files in the folder have been deleted!"
  'End Try
  'Return String.Empty

 End Function

 Public Overrides Function DeleteFile(ByVal path As String) As String
  'DotNetNuke.Common.Utilities.FileSystemUtils.DeleteFile(AbsolutePath(path), Portalsettings, True)
  Dim Entry As EntryInfo = GetEntryFromPath(path)
  If Entry IsNot Nothing Then
   If Entry.CanEdit Then
    Entry.Delete(True)
   Else
    Return "Not Allowed"
   End If
  Else
   Return "Not Found"
  End If
  Return String.Empty
 End Function

 Public Overrides Function Equals(ByVal obj As Object) As Boolean
  Return MyBase.Equals(obj)
 End Function

 Public Overrides Function GetFile(ByVal url As String) As System.IO.Stream
  Return MyBase.GetFile(url.Replace("//", "/"))
 End Function

 Public Overrides Function GetFileName(ByVal url As String) As String
  Return MyBase.GetFileName(url.Replace("//", "/"))
 End Function

 Public Overrides Function GetHashCode() As Integer
  Return MyBase.GetHashCode()
 End Function

 Public Overrides Function GetPath(ByVal url As String) As String
  Return MyBase.GetPath(url.Replace("//", "/"))
 End Function

 Protected Overrides Function IsValid(ByVal directory As System.IO.DirectoryInfo) As Boolean
  Return MyBase.IsValid(directory)
 End Function

 Protected Overrides Function IsValid(ByVal file As System.IO.FileInfo) As Boolean
  Return MyBase.IsValid(file)
 End Function

 Public Overrides Function MoveDirectory(ByVal path As String, ByVal newPath As String) As String

  Dim entryToMove As EntryInfo = GetEntryFromPath(path)
  If entryToMove Is Nothing Then
   Return "Did not find source folder"
  End If
  Dim TargetFolder As EntryInfo = GetEntryFromPath(newPath)
  If TargetFolder Is Nothing Then
   Return "Did not find target folder"
  End If
  Return EntriesController.MoveEntry(PortalId, entryToMove.EntryId, UserId, TargetFolder.EntryId)

 End Function

 Public Overrides Function MoveFile(ByVal path As String, ByVal newPath As String) As String

  Dim entryToMove As EntryInfo = GetEntryFromPath(path)
  If entryToMove Is Nothing Then
   Return "Did not find source file"
  End If
  Dim TargetFolder As EntryInfo = GetEntryFromPath(newPath)
  If TargetFolder Is Nothing Then
   Return "Did not find target folder"
  End If
  Return EntriesController.MoveEntry(PortalId, entryToMove.EntryId, UserId, TargetFolder.EntryId)

 End Function

 Public Overrides Function StoreBitmap(ByVal bitmap As System.Drawing.Bitmap, ByVal url As String, ByVal format As System.Drawing.Imaging.ImageFormat) As String
  ' todo: not sure what should happen here
  Return MyBase.StoreBitmap(bitmap, url, format)
 End Function

 Public Overrides Function StoreFile(ByVal file As Telerik.Web.UI.UploadedFile, ByVal path As String, ByVal name As String, ByVal ParamArray arguments() As String) As String

  AddFile(Portalsettings.PortalId, file.InputStream, AbsolutePath(path & file.GetName), file.ContentType, file.ContentLength, path, True, True, False)

  Return String.Empty

 End Function

 Public Overrides Function ToString() As String
  Return MyBase.ToString()
 End Function

#End Region

#Region " Private Listing Methods "

 Private Function GetChildDirectories(ByVal objParent As EntryInfo, ByVal path As String) As DirectoryItem()

  If Not DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString) Is Nothing Then
   Return CType(DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString), DirectoryItem())
  End If

  Dim directories As New List(Of DirectoryItem)

  Dim Folderlist As List(Of EntryInfo) = EntriesController.GetSubCollections(PortalId, objParent.EntryId, UserId, False, Threading.Thread.CurrentThread.CurrentCulture.Name)

  For Each objFolder As EntryInfo In Folderlist
   Dim fpath As String = objFolder.FullPath(False, Threading.Thread.CurrentThread.Name)
   directories.Add(New DirectoryItem(objFolder.Title, String.Empty, fpath, fpath, GetEntryPermissions(objFolder), GetChildFiles(objFolder, path), GetChildDirectories(objFolder, path)))
  Next

  If directories.Count > 0 Then
   DataCache.SetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString, directories.ToArray)
   Return directories.ToArray
  End If

  DataCache.SetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString, New DirectoryItem() {})
  Return New DirectoryItem() {}

 End Function

 Private Function GetChildFiles(ByVal objParent As EntryInfo, ByVal path As String) As FileItem()

  If Not DataCache.GetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString) Is Nothing Then
   Return CType(DataCache.GetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString), FileItem())
  End If

  Dim files As New ArrayList()
  Dim fileList As List(Of EntryInfo) = EntriesController.GetCollectionContents(PortalId, objParent.EntryId, UserId, False, Threading.Thread.CurrentThread.Name, True, True, False, False)

  Dim folderPermission As PathPermissions = GetEntryPermissions(objParent)

  For Each objFile As EntryInfo In fileList

   If objFile.IsFile Then

    Dim filePermission As PathPermissions = PathPermissions.Read
    If objFile.CanEdit Then
     filePermission = filePermission Or PathPermissions.Delete
    End If
    If SearchPatterns.Length = 1 Then
     If SearchPatterns(0) = "*.*" Then
      files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), objFile.FileSize, CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId.ToString, folderPermission))
     End If
    ElseIf (SearchPatterns.Length > 0) Then
     For Each strExtension As String In SearchPatterns
      If strExtension = "*.*" Then
       files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), objFile.FileSize, CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId.ToString, folderPermission))
      Else
       If strExtension.ToLower.Replace(".", "").Replace("*", "") = IO.Path.GetExtension(objFile.OriginalFileName).ToLower.Replace(".", "") Then
        files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), objFile.FileSize, CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId.ToString, folderPermission))
       End If
      End If
     Next
    Else
     files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), objFile.FileSize, CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId.ToString, folderPermission))
    End If

   End If


  Next

  If fileList.Count > 0 Then
   DataCache.SetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString, DirectCast(files.ToArray(GetType(FileItem)), FileItem()))
   Return DirectCast(files.ToArray(GetType(FileItem)), FileItem())
  End If

  DataCache.SetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString, New FileItem() {})
  Return New FileItem() {}

 End Function

#End Region

#Region "Private Helper Methods"

 Private Function GetDownloadUrl(ByVal EntryId As Integer) As String
  Return ResolveUrl("~/Desktopmodules/Bring2Mind/DMX/Download.aspx?EntryId=" & EntryId & "&PortalId=" & Portalsettings.PortalId.ToString)
 End Function

 Private Function GetEntryFromPath(ByVal path As String) As EntryInfo

  Dim requestedEntry As EntryInfo = Nothing
  Dim cleanedPath As String = CleanPath(path)
  If String.IsNullOrEmpty(cleanedPath) OrElse cleanedPath = "/" Then
   requestedEntry = EntriesController.GetRootEntry(PortalId)
  Else
   requestedEntry = EntriesController.GetEntryByDavPath(PortalId, UserId, glbWebdavHandler & "/" & cleanedPath)
  End If
  Return requestedEntry

 End Function

 Private Function GetEntryPermissions(ByVal objEntry As EntryInfo) As PathPermissions
  Dim res As PathPermissions = PathPermissions.Read ' by definition or else we wouldn't see it
  If objEntry.CanAdd Then
   res = res Or PathPermissions.Upload
  End If
  If objEntry.CanEdit Then
   res = res Or PathPermissions.Delete
  End If
  Return res
 End Function

 Private Function AddFile(ByVal PortalId As Integer, ByVal inStream As Stream, ByVal fileName As String, ByVal contentType As String, ByVal length As Long, ByVal folderName As String, ByVal closeInputStream As Boolean, ByVal clearCache As Boolean, ByVal synchronize As Boolean) As String

  Dim objFolder As EntryInfo = GetEntryFromPath(folderName)
  Dim sourceFileName As String = System.IO.Path.GetFileName(fileName).Replace(glbProtectedExtension, "")
  Dim retValue As String = ""

  retValue += CheckValidFileName(fileName)
  If retValue.Length > 0 Then
   Return retValue
  End If

  Try
   EntriesController.SimplifiedUpload(PortalId, objFolder.EntryId, inStream, sourceFileName, IO.Path.GetFileNameWithoutExtension(sourceFileName), Portalsettings.UserInfo, False)
  Catch ex As Exception
   retValue = ex.Message
  End Try

  Return retValue

 End Function

 Private Shared Function CheckValidFileName(ByVal strFileName As String) As String

  Dim retValue As String = String.Empty
  If strFileName.IndexOf("'") > -1 Then
   retValue = "InvalidFileName"
  End If

  'Return
  Return retValue

 End Function

 Private Function GetDirectoryPath(ByVal path As String) As String
  Return path.Substring(0, path.LastIndexOf("/"c) + 1)
 End Function

 Private Function IsChildOf(ByVal parentPath As String, ByVal childPath As String) As Boolean
  Return childPath.StartsWith(parentPath)
 End Function

 Private Function EndWithSlash(ByVal path As String) As String
  If Not path.EndsWith("/") Then
   Return path & "/"
  End If
  Return path
 End Function

 Private Function CombinePath(ByVal path1 As String, ByVal path2 As String) As String
  If path1.EndsWith("/") Then
   Return String.Format("{0}{1}", path1, path2)
  End If
  If path1.EndsWith("\") Then
   path1 = path1.Substring(0, path1.Length - 1)
  End If
  Return String.Format("{0}/{1}", path1, path2)
 End Function

 Private Function GetItemUrl(ByVal virtualItemPath As String) As String
  Return String.Format("{0}?path={1}", ItemHandlerPath, virtualItemPath)
 End Function

 Private Function ExtractPath(ByVal itemUrl As String) As String
  If itemUrl Is Nothing Then
   Return String.Empty
  End If
  If itemUrl.StartsWith(_itemHandlerPath) Then
   Return itemUrl.Substring(GetItemUrl(String.Empty).Length)
  End If
  Return itemUrl
 End Function

 Private Function GetName(ByVal Path As String) As String
  Dim strPath As String = String.Empty
  If Path Is Nothing Then
   Return String.Empty
  End If
  If EndWithSlash(Path) = EndWithSlash(Portalsettings.HomeDirectory) Then
   Return "DMX"
  End If
  If Path.Contains("/") Then
   strPath = Path.Substring(Path.LastIndexOf("/") + 1)
  End If
  If strPath = String.Empty Then
   Return "DMX"
  End If
  Return strPath
 End Function

 Private Function IsExtensionAllowed(ByVal extension As String) As Boolean
  Return Array.IndexOf(SearchPatterns, "*.*") >= 0 OrElse Array.IndexOf(SearchPatterns, "*" & extension.ToLower()) >= 0
 End Function

 Private Function RemoveLastSlash(ByVal path As String) As String
  If path.EndsWith("/") Then
   Return path.Substring(0, path.Length - 1)
  End If
  Return path
 End Function

 Private Function CleanPath(ByVal path As String) As String
  If String.IsNullOrEmpty(DMXPath) Then Return path
  If path.StartsWith(DMXPath) Then
   path = Mid(path, DMXPath.Length + 1)
  End If
  Return path
 End Function


 Private Function AbsolutePath(ByVal path As String) As String
  path = CleanPath(path)
  Dim absPath As String = Portalsettings.HomeDirectoryMapPath
  absPath += path
  Return absPath
 End Function

#End Region

End Class
